home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PCMania 21
/
PCMania CD21.nrg
/
sharewar
/
drum
/
drumdll.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-12
|
5KB
|
169 lines
/*------------------------------------------
DRUMDLL.C -- DLL module for DRUM program
(c) Charles Petzold, 1992
------------------------------------------*/
#include <windows.h>
extern "C" {
#include <mmsystem.h>
}
#include <string.h>
#include "drumdll.h"
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define minmax(a,x,b) (min (max (x, a), b))
#define TIMER_RES 5
void FAR PASCAL _export DrumTimerFunc (WORD, WORD, DWORD, DWORD, DWORD) ;
BOOL bSequenceGoing, bEndSequence ;
DRUM drum ;
HMIDIOUT hMidiOut ;
HWND hwndNotify ;
int iIndex ;
WORD wTimerRes, wTimerID ;
int FAR PASCAL LibMain (HANDLE hInstance, WORD wDataSeg, WORD wHeapSize,
LPSTR lpszCmdLine)
{
return 1 ;
}
DWORD MidiOutMessage (HMIDIOUT hMidi, int iStatus, int iChannel,
int iData1, int iData2)
{
DWORD dwMessage ;
dwMessage = iStatus | iChannel | (iData1 << 8) | ((long) iData2 << 16) ;
return midiOutShortMsg (hMidi, dwMessage) ;
}
void FAR PASCAL _export DrumSetParams (PDRUM pdrum)
{
_fmemcpy (&drum, pdrum, sizeof (DRUM)) ;
}
BOOL FAR PASCAL _export DrumBeginSequence (HWND hwnd)
{
TIMECAPS tc ;
hwndNotify = hwnd ; // Save window handle for notification
DrumEndSequence (TRUE) ; // Stop current sequence if running
// Open the MIDI Mapper output port
if (midiOutOpen (&hMidiOut, (WORD) MIDIMAPPER, NULL, NULL, 0L))
return FALSE ;
// Send Program Change messages for channels 9 and 15
MidiOutMessage (hMidiOut, 0xC0, 9, 0, 0) ;
MidiOutMessage (hMidiOut, 0xC0, 15, 0, 0) ;
// Begin sequence by setting a timer event
timeGetDevCaps (&tc, sizeof (TIMECAPS)) ;
wTimerRes = minmax (tc.wPeriodMin, TIMER_RES, tc.wPeriodMax) ;
timeBeginPeriod (wTimerRes) ;
wTimerID = timeSetEvent (max ((int) wTimerRes, drum.iMsecPerBeat),
wTimerRes, DrumTimerFunc, 0L, TIME_ONESHOT) ;
if (wTimerID == 0)
{
timeEndPeriod (wTimerRes) ;
midiOutClose (hMidiOut) ;
return FALSE ;
}
iIndex = -1 ;
bEndSequence = FALSE ;
bSequenceGoing = TRUE ;
return TRUE ;
}
void FAR PASCAL _export DrumEndSequence (BOOL bRightAway)
{
if (bRightAway)
{
if (bSequenceGoing)
{
// stop the timer
if (wTimerID)
timeKillEvent (wTimerID) ;
timeEndPeriod (wTimerRes) ;
// turn off all notes
MidiOutMessage (hMidiOut, 0xB0, 9, 123, 0) ;
MidiOutMessage (hMidiOut, 0xB0, 15, 123, 0) ;
// close the MIDI port
midiOutClose (hMidiOut) ;
bSequenceGoing = FALSE ;
}
}
else
bEndSequence = TRUE ;
}
void FAR PASCAL _export DrumTimerFunc (WORD wID, WORD wMsg, DWORD dwUser,
DWORD dw1, DWORD dw2)
{
static DWORD dwSeqExtLast [NUM_PERC], dwSeqBasLast [NUM_PERC] ;
int i ;
// Note Off messages for channels 9 and 15
if (iIndex != -1)
{
for (i = 0 ; i < NUM_PERC ; i++)
{
if (dwSeqExtLast[i] & 1L << iIndex)
MidiOutMessage (hMidiOut, 0x80, 9, i + 35, 0) ;
if (dwSeqBasLast[i] & 1L << iIndex) ;
MidiOutMessage (hMidiOut, 0x80, 15, i + 35, 0) ;
}
}
// Increment index and notify window to advance bouncing ball
iIndex = (iIndex + 1) % drum.iNumBeats ;
PostMessage (hwndNotify, WM_USER_NOTIFY, iIndex, timeGetTime ()) ;
// Check if ending the sequence
if (bEndSequence && iIndex == 0)
{
PostMessage (hwndNotify, WM_USER_FINISHED, 0, 0L) ;
return ;
}
// Note On messages for channels 9 and 15
for (i = 0 ; i < NUM_PERC ; i++)
{
if (drum.dwSeqExt[i] & 1L << iIndex)
MidiOutMessage (hMidiOut, 0x90, 9, i + 35, drum.iVelocity) ;
if (drum.dwSeqBas[i] & 1L << iIndex)
MidiOutMessage (hMidiOut, 0x90, 15, i + 35, drum.iVelocity) ;
dwSeqExtLast[i] = drum.dwSeqExt[i] ;
dwSeqBasLast[i] = drum.dwSeqBas[i] ;
}
// Set a new timer event
wTimerID = timeSetEvent (max ((int) wTimerRes, drum.iMsecPerBeat),
wTimerRes, DrumTimerFunc, 0L, TIME_ONESHOT) ;
if (wTimerID == 0)
{
PostMessage (hwndNotify, WM_USER_ERROR, 0, 0L) ;
}
}